/**
 * 
 */
package edu.cmu.cs.webapp.ioms.views;

import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;

import edu.cmu.cs.webapp.ioms.dao.DataAccessException;
import edu.cmu.cs.webapp.ioms.dao.impl.ClientDAOImpl;
import edu.cmu.cs.webapp.ioms.dao.impl.OrderDAOImpl;
import edu.cmu.cs.webapp.ioms.logging.Alerts;
import edu.cmu.cs.webapp.ioms.models.Client;
import edu.cmu.cs.webapp.ioms.models.OrderStatus;
import edu.cmu.cs.webapp.ioms.models.PurchaseOrder;
import edu.cmu.cs.webapp.ioms.models.impl.PurchaseOrderImpl;
import edu.cmu.cs.webapp.ioms.ui.providers.order.CustomersTableViewerContentProvider;
import edu.cmu.cs.webapp.ioms.ui.providers.order.CustomersTableViewerLabelProvider;
import edu.cmu.cs.webapp.ioms.utils.IOMSConstants;
import edu.cmu.cs.webapp.ioms.utils.IOMSImageHelper;
import edu.cmu.cs.webapp.ioms.utils.IOMSImages;
import edu.cmu.cs.webapp.ioms.utils.IOMSUtils;
import edu.cmu.cs.webapp.ioms.utils.SWTUtils;

/**
 * @author Christian
 * 
 */
public class CustomersListView extends ViewPart implements ISelectionProvider {
	public static final String ID_VIEW = "edu.cmu.cs.webapp.ioms.views.customerslist";

	private TableViewer viewer;
	private CustomerFilter viewerFilter;

	private Table table;
	private Combo searchChoice;
	private Text searchText;
	ITableLabelProvider labelProvider;

	private SashForm form;

	private Composite _viewerComp;

	private Group _orderGroup;

	private Table ordersTable;
	private TableViewer ordersViewer;

	private Client[] customers;

//	private Text _totalSalesTxt;

	/**
	 * 
	 */
	public CustomersListView() {
		viewerFilter = new CustomerFilter();
		labelProvider = new CustomersTableViewerLabelProvider();
	}

	@Override
	public void init(IViewSite site) throws PartInitException {
		super.init(site);
		site.setSelectionProvider(this);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets
	 * .Composite)
	 */
	@Override
	public void createPartControl(Composite parent) {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 1;
		gridLayout.marginHeight = 0;
		gridLayout.marginWidth = 0;

		parent.setLayout(gridLayout);

		createFilterGroup(parent);

		form = new SashForm(parent, SWT.HORIZONTAL);
		GridData gd = new GridData(GridData.FILL_BOTH);
		gd.grabExcessHorizontalSpace = true;
		gd.grabExcessVerticalSpace = true;
		form.setLayoutData(gd);
		this._viewerComp = SWTUtils.createComposite(form, 1);
		createTableViewer(_viewerComp);

		this._orderGroup = SWTUtils.createGroup(form, "Placed Orders", 3);
		createCustomerOrdersGroup(this._orderGroup);
		// SWTUtils.createLabel(_orderGroup, "Total Sales:", 1);
		// this._totalSalesTxt = SWTUtils.createTextBox(_orderGroup, 2);

		form.setWeights(new int[] { 2, 1 });
		form.setMaximizedControl(_viewerComp);

	}

	private void createCustomerOrdersGroup(Group orderGroup) {
		/*
		 * Create table
		 */
		GridData gridData = new GridData();
		gridData.horizontalSpan = 3;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		gridData.verticalAlignment = GridData.FILL;

		ordersTable = new Table(orderGroup, SWT.SINGLE | SWT.BORDER
				| SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);

		ordersTable.setLayoutData(gridData);
		ordersTable.setHeaderVisible(true);
		// ordersTable.setLinesVisible(true);

		TableColumn dateColumn = new TableColumn(ordersTable, SWT.NONE);
		dateColumn.setText("Order Date"); //$NON-NLS-1$
		dateColumn.setWidth(100);

		TableColumn statusColumn = new TableColumn(ordersTable, SWT.NONE);
		statusColumn.setText("Order Status"); //$NON-NLS-1$
		statusColumn.setWidth(100);

		TableColumn nameColumn = new TableColumn(ordersTable, SWT.NONE);
		nameColumn.setText("Gross Sales"); //$NON-NLS-1$
		nameColumn.setWidth(110);

		/*
		 * Create viewer
		 */
		ordersViewer = new TableViewer(ordersTable);

		ordersViewer.setLabelProvider(new ITableLabelProvider() {

			public Image getColumnImage(Object element, int columnIndex) {
				if (element instanceof PurchaseOrder) {
					PurchaseOrder order = (PurchaseOrder) element;
					Image img = null;
					if (order.getStatus().equals(OrderStatus.INPROCESS)) {
						img = IOMSImageHelper.getInstance().getImage(
								IOMSImages.IMG_ORDER_INPROCESS);
					} else if (order.getStatus().equals(OrderStatus.PENDING)) {
						img = IOMSImageHelper.getInstance().getImage(
								IOMSImages.IMG_ORDER_PENDING);
					} else if (order.getStatus().equals(OrderStatus.DELIVERED)) {
						img = IOMSImageHelper.getInstance().getImage(
								IOMSImages.IMG_ORDER_DELIVERED);
					} else if (order.getStatus().equals(OrderStatus.ACCEPTED)) {
						img = IOMSImageHelper.getInstance().getImage(
								IOMSImages.IMG_ORDER_ACCEPT);
					}

					switch (columnIndex) {
					case 1:
						return img;
					}
				}
				return null;
			}

			public String getColumnText(Object element, int columnIndex) {
				if (element instanceof PurchaseOrder) {
					PurchaseOrder order = (PurchaseOrder) element;
					switch (columnIndex) {
					case 0:
						return DateFormat.getDateInstance().format(
								order.getOrder_date());
					case 1:
						return order.getStatus().getLiteral();
					case 2:
						return NumberFormat.getCurrencyInstance().format(
								((PurchaseOrderImpl) order).getGrossSales());
					default:
						return "";
					}
				}
				return "";
			}

			public void addListener(ILabelProviderListener listener) {
			}

			public void dispose() {
			}

			public boolean isLabelProperty(Object element, String property) {
				return false;
			}

			public void removeListener(ILabelProviderListener listener) {

			}

		});
		ordersViewer.setContentProvider(new IStructuredContentProvider() {

			public Object[] getElements(Object inputElement) {
				if (inputElement instanceof PurchaseOrder[]) {
					return (PurchaseOrder[]) inputElement;
				}
				return new Object[0];
			}

			public void dispose() {

			}

			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {

			}
		});

		addSelectionChangedListener(new ISelectionChangedListener() {

			@Override
			public void selectionChanged(SelectionChangedEvent event) {
				Object sel = ((IStructuredSelection) event.getSelection())
						.getFirstElement();
				if (sel != null && sel instanceof Client) {
					Map<String, Object> searchCriteria = new HashMap<String, Object>();
					searchCriteria.put(IOMSConstants.CLIENT_CLIENT_ID,
							((Client) sel).getClient_id());

					try {
						ordersViewer.setInput(new OrderDAOImpl().searchOrders(
								searchCriteria).toArray(new PurchaseOrder[0]));
					} catch (DataAccessException e) {

					}
				}

			}
		});
	}

	private void createFilterGroup(Composite parent) {

		Composite composite = new Composite(parent, SWT.NONE);
		GridData gridCompositeData = new GridData();
		gridCompositeData.verticalAlignment = GridData.BEGINNING;
		gridCompositeData.horizontalAlignment = GridData.FILL;
		gridCompositeData.grabExcessHorizontalSpace = true;

		composite.setLayoutData(gridCompositeData);

		GridLayout gridCompositeGroupLayout = new GridLayout();
		gridCompositeGroupLayout.numColumns = 3;
		composite.setLayout(gridCompositeGroupLayout);

		Label searchLabel = new Label(composite, SWT.NONE);
		searchLabel.setText("Filter By:"); //$NON-NLS-1$

		searchChoice = SWTUtils.createCombo(composite, new String[] {
				"Customer ID", "First Name", "Last Name", "Email", "Phone",
				"Company", "Address", "City", "State", "Country" }, 1);
		searchChoice.select(0);

		searchText = new Text(composite, SWT.BORDER);
		GridData txtGridData = new GridData(GridData.FILL_HORIZONTAL);
		txtGridData.horizontalAlignment = SWT.FILL;
		txtGridData.grabExcessHorizontalSpace = true;
		searchText.setLayoutData(txtGridData);
		searchText.addModifyListener(new ModifyListener() {

			@Override
			public void modifyText(ModifyEvent event) {
				Text text = (Text) event.widget;
				viewerFilter.setText(text.getText());
				viewer.refresh();
			}
		});

	}

	public void createTableViewer(Composite parent) {

		/*
		 * Create table
		 */
		GridData gridData = new GridData();
		gridData.horizontalSpan = 3;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = GridData.FILL;
		gridData.verticalAlignment = GridData.FILL;

		table = new Table(parent, SWT.FULL_SELECTION | SWT.BORDER
				| SWT.H_SCROLL | SWT.V_SCROLL);
		table.setLayoutData(gridData);

		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		// id
		TableColumn idColumn = new TableColumn(table, SWT.NONE);
		idColumn.setText("#"); //$NON-NLS-1$
		idColumn.setWidth(60);
		idColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.ClIENT_ID,
						sortDirection == SWT.DOWN));
			}
		});

		// first name
		TableColumn fnameColumn = new TableColumn(table, SWT.NONE);
		fnameColumn.setText("First Name"); //$NON-NLS-1$
		fnameColumn.setWidth(100);
		fnameColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.FNAME,
						sortDirection == SWT.DOWN));
			}
		});

		// Last Name
		TableColumn lnameColumn = new TableColumn(table, SWT.NONE);
		lnameColumn.setText("Last Name"); //$NON-NLS-1$
		lnameColumn.setWidth(100);
		lnameColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.LNAME,
						sortDirection == SWT.DOWN));
			}
		});

		// Email
		TableColumn emailColumn = new TableColumn(table, SWT.NONE);
		emailColumn.setText("Email"); //$NON-NLS-1$
		emailColumn.setWidth(100);
		emailColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.EMAIL,
						sortDirection == SWT.DOWN));
			}
		});

		// phone
		TableColumn phoneColumn = new TableColumn(table, SWT.NONE);
		phoneColumn.setText("Phone"); //$NON-NLS-1$
		phoneColumn.setWidth(90);
		phoneColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.PHONE,
						sortDirection == SWT.DOWN));
			}
		});

		// company
		TableColumn compColumn = new TableColumn(table, SWT.NONE);
		compColumn.setText("Company"); //$NON-NLS-1$
		compColumn.setWidth(100);
		compColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.COMPANY,
						sortDirection == SWT.DOWN));
			}
		});

		// address
		TableColumn addrColumn = new TableColumn(table, SWT.NONE);
		addrColumn.setText("Address"); //$NON-NLS-1$
		addrColumn.setWidth(170);
		addrColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.ADDRESS,
						sortDirection == SWT.DOWN));
			}
		});

		// city
		TableColumn cityColumn = new TableColumn(table, SWT.NONE);
		cityColumn.setText("City"); //$NON-NLS-1$
		cityColumn.setWidth(100);
		cityColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.CITY,
						sortDirection == SWT.DOWN));
			}
		});

		// state
		TableColumn stateColumn = new TableColumn(table, SWT.NONE);
		stateColumn.setText("State"); //$NON-NLS-1$
		stateColumn.setWidth(90);
		stateColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.STATE,
						sortDirection == SWT.DOWN));
			}
		});

		// country
		TableColumn countryColumn = new TableColumn(table, SWT.NONE);
		countryColumn.setText("Country"); //$NON-NLS-1$
		countryColumn.setWidth(90);
		countryColumn.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				int sortDirection = IOMSUtils
						.updateSortDirection((TableColumn) e.widget);
				viewer.setSorter(new CustomerSorter(
						CustomersTableViewerLabelProvider.COUNTRY,
						sortDirection == SWT.DOWN));
			}
		});

		/*
		 * Create viewer
		 */
		viewer = new TableViewer(table);

		viewer.setUseHashlookup(true);
		viewer.addFilter(viewerFilter);

		viewer.setLabelProvider(labelProvider);
		viewer.setContentProvider(new CustomersTableViewerContentProvider());

		// tableViewer.setComparator(new
		// TableViewerComparator(this.tableViewer));

		refreshCustomersView();
	}

	/**
	 * 
	 */
	public void refreshCustomersView() {

		UIJob refreshJob = new RefreshJob("Refresh");
		refreshJob.setUser(true);
		refreshJob.schedule();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
	 */
	@Override
	public void setFocus() {

	}

	public void hideCustomerOrdersView(boolean hide) {
		if (hide) {
			this.form.setMaximizedControl(_viewerComp);
		} else {
			this.form.setMaximizedControl(null);
		}
	}

	private final class CustomerFilter extends ViewerFilter {
		private String text;

		public void setText(final String s) {
			this.text = s;
		}

		@Override
		public boolean select(final Viewer viewer, final Object parentElement,
				final Object element) {
			boolean result = true;
			if (text != null && text.length() > 0) {
				String txt = labelProvider.getColumnText(element, searchChoice
						.getSelectionIndex());
				result = txt.toLowerCase().indexOf(text.toLowerCase()) != -1;
			}
			return result;
		}

		@Override
		public boolean isFilterProperty(final Object element, final String prop) {
			return true;
		}
	}

	@Override
	public void addSelectionChangedListener(ISelectionChangedListener listener) {
		this.viewer.addSelectionChangedListener(listener);

	}

	@Override
	public ISelection getSelection() {
		return this.viewer.getSelection();
	}

	@Override
	public void removeSelectionChangedListener(
			ISelectionChangedListener listener) {
		this.viewer.removeSelectionChangedListener(listener);

	}

	@Override
	public void setSelection(ISelection selection) {
		this.viewer.setSelection(selection);

	}

	/**
	 * 
	 * @author Christian
	 * 
	 */
	private class RefreshJob extends UIJob {

		public RefreshJob(String name) {
			super(name);
		}

		@Override
		public IStatus runInUIThread(IProgressMonitor monitor) {
			monitor.beginTask("Refreshing Customers List...",
					IProgressMonitor.UNKNOWN);
			try {
				customers = new ClientDAOImpl().getAllClient().toArray(
						new Client[0]);

			} catch (DataAccessException e) {
				Alerts.getInstance().detailError("Data Access Error",
						e.getLocalizedMessage(), e);
				return Status.CANCEL_STATUS;
			}

			if (customers != null) {
				viewer.setInput(customers);
			}

			monitor.done();

			return Status.OK_STATUS;
		}

	}

	/**
	 * 
	 * @param site
	 * @return
	 */
	public static CustomersListView getCustomersListViewPart(IViewSite site) {
		IViewPart view = site.getPage().findView(CustomersListView.ID_VIEW);
		if (view instanceof CustomersListView) {
			return ((CustomersListView) view);
		}
		return null;
	}

	private class CustomerSorter extends ViewerSorter {
		private int columnIndex;
		private final boolean ascending;

		public CustomerSorter(int criteria, boolean ascending) {
			super();
			this.columnIndex = criteria;
			this.ascending = ascending;
		}

		@SuppressWarnings("unchecked")
		@Override
		public int compare(Viewer viewer, Object e1, Object e2) {
			int result = 0;
			if (e1 instanceof Client && e2 instanceof Client) {
				result = getComparator().compare(
						labelProvider.getColumnText(e1, columnIndex),
						labelProvider.getColumnText(e2, columnIndex));
			}

			if (!ascending) {
				result = result * -1;
			}
			return result;
		}
	}
}
